package com.alibaba.citrus.cr.sales.plan.facade.service.setting.contract.strategy.category;

import com.alibaba.citrus.cr.common.annotation.FacadeInvoker;
import com.alibaba.citrus.cr.sales.plan.api.setting.contract.trategy.ContractStatStrategy;
import com.alibaba.citrus.cr.sales.plan.dto.api.request.PageQueryContractRequest;
import com.alibaba.citrus.cr.sales.plan.facade.utils.ObjectEqualsUtil;
import com.alibaba.citrus.cr.sales.plan.functions.contract.ContractAbility;
import com.alibaba.citrus.cr.sales.plan.model.enums.ContractDataSourceEnum;
import com.alibaba.citrus.cr.sales.plan.model.enums.ContractStatDimensionEnum;
import com.alibaba.citrus.cr.sales.plan.repository.ContractRepository;
import com.alibaba.citrus.cr.sales.plan.sdo.ContractSDO;
import com.alibaba.cz.base.tool.MapUtil;
import com.alibaba.cz.base.tool.Nullable;
import com.alibaba.cz.base.tool.StringUtil;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.cz.base.tool.page.PageResult;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author wangyibing
 */
@Component("companyCategoryCategoryDimension")
public class ContractCompanyCategoryStrategyImpl implements ContractStatStrategy {
    private final Log log = Log.getLogger(ContractCompanyCategoryStrategyImpl.class);
    @Resource
    private ContractRepository contractRepository;

    @Resource
    private ContractAbility contractAbility;

    @Override
    @FacadeInvoker
    public boolean summary(String contractYear) {
        //1、分组查询公司类目维度的合同量明细
        List<ContractSDO> contractSDOList = contractRepository.queryGroupByCompanyCategory(contractYear);
        //2、批量插入上一步查出来的合同量list
        Integer integer = contractAbility.batchCreateContract(contractSDOList);
        if (integer < 1) {
            log.error("合同年月:{}批量插入合同量失败", contractYear);
        }
        return contractSDOList.size() == integer;
    }

    @Override
    public String summaryV2(List<ContractSDO> contractList, String year, String orgBusinessUnitCode) {
        //1、汇总公司类目维度的合同量明细
        List<ContractSDO> groupContractList = summaryContract(contractList);
        log.info("companyCategoryCategoryDimension_summaryV2_groupList_size={}", groupContractList.size());
        //2、查询当前汇总的合同量明细
        Map<String,ContractSDO> summaryContractMap = getSummaryContractMap(year,orgBusinessUnitCode);
        log.info("companyCategoryCategoryDimension_summaryV2_summaryContractMap_size={}", summaryContractMap.size());

        //3、比较
        List<ContractSDO> createList = new ArrayList<>();
        List<ContractSDO> updateList = new ArrayList<>();
        int count = 0;
        for(ContractSDO sdo :groupContractList){
            ContractSDO summaryContract = summaryContractMap.get(getkey(sdo));
            if(summaryContract == null){
                createList.add(sdo);
            }else{
                summaryContract.setFeatures("1");
                if(ObjectEqualsUtil.domainEquals(sdo,summaryContract,equalFields)){
                    count++;
                }else{
                    sdo.setId(summaryContract.getId());
                    updateList.add(sdo);
                }
            }
        }
        log.info("companyCategoryCategoryDimension_summaryV2_nodeal_size={}", count);
        log.info("companyCategoryCategoryDimension_summaryV2_createList_size={}", createList.size());
        log.info("companyCategoryCategoryDimension_summaryV2_updateList_size={}", updateList.size());

        //4、数据库数据更新
        if(CollectionUtils.isNotEmpty(createList)){
            Integer integer = contractAbility.batchCreateContract(createList);
            count = count + integer;
            log.info("companyCategoryCategoryDimension_summaryV2_batchCreateContract_size={}", integer);
        }
        if(CollectionUtils.isNotEmpty(updateList)){
            Integer integer = 0;
            for(ContractSDO sdo:updateList){
                Integer i = contractAbility.updateSummaryContract(sdo);
                integer = integer + i;
            }
            count = count + integer;
            log.info("companyCategoryCategoryDimension_summaryV2_batchUpdateContract_size={}", integer);
        }

        //5.删除未对比数据
        if(MapUtils.isNotEmpty(summaryContractMap)){
            List<ContractSDO> deleteList = summaryContractMap.values().stream().filter(x->StringUtil.isBlank(x.getFeatures())).collect(Collectors.toList());
            List<Long> ids = Nullable.stream(deleteList).map(x->x.getId()).collect(Collectors.toList());
            Integer integer = contractAbility.deleteContractByIds(ids);
            log.info("ContractWriteServiceImpl_summaryContractByYear_deleteContractByIds_request={},result_size={}",ids,integer);
        }

        return "COMPANY_CATEGORY:"+count;
    }

    private Map<String,ContractSDO> getSummaryContractMap(String year, String orgBusinessUnitCode){
        int pageSize = 1000;
        PageQueryContractRequest pageQueryContractRequest = new PageQueryContractRequest();
        pageQueryContractRequest.setContractYear(year);
        pageQueryContractRequest.setType(ContractStatDimensionEnum.COMPANY_CATEGORY.getCode());
        pageQueryContractRequest.setOrgBusinessUnitCode(orgBusinessUnitCode);
        pageQueryContractRequest.setDataSource(ContractDataSourceEnum.CUSTOMER.getCode());
        pageQueryContractRequest.setStart(0);
        pageQueryContractRequest.setSize(pageSize);
        PageResult<List<ContractSDO>> pageResult = contractRepository.simplePageQueryContract(pageQueryContractRequest);
        List<ContractSDO> resultList = pageResult.getContent();
        if(CollectionUtils.isEmpty(resultList)){
            return new HashMap<String,ContractSDO>();
        }

        if(pageResult.getTotal()>pageSize){
            int totalPage = pageResult.getTotal()/pageSize;
            if (pageResult.getTotal()%pageSize>0){
                totalPage++;
            }
            for (int pageNo = 1; pageNo < totalPage; pageNo++) {
                int start = pageNo*pageSize;
                pageQueryContractRequest.setStart(start);
                PageResult<List<ContractSDO>> pageResult2 = contractRepository.simplePageQueryContract(pageQueryContractRequest);
                resultList.addAll(pageResult2.getContent());
            }
        }

        Map<String,ContractSDO> resultMap = resultList.stream().collect(Collectors.toMap(x->getkey(x), Function.identity(),(v1, v2)->v1));
        return resultMap;
    }

    private List<ContractSDO> summaryContract(List<ContractSDO> contractList){
        Map<String, List<ContractSDO>> map = contractList.stream().collect(Collectors.groupingBy(x->getkey(x)));
        List<ContractSDO> result = new ArrayList<>();
        for (Map.Entry<String, List<ContractSDO>> m : map.entrySet()) {
            List<ContractSDO> list = m.getValue();
            ContractSDO combineSdo = new ContractSDO();
            combineGroup(combineSdo,list);
            result.add(combineSdo);
        }
        return result;
    }

    private void combineGroup(ContractSDO contractSDO,List<ContractSDO> list){
        contractSDO.setType(ContractStatDimensionEnum.COMPANY_CATEGORY.getCode());
        contractSDO.setDataSource(ContractDataSourceEnum.CUSTOMER.getCode());
        contractSDO.setContractYear(list.get(0).getContractYear());
        contractSDO.setOrgBusinessUnitCode(list.get(0).getOrgBusinessUnitCode());
        contractSDO.setScItemCategoryId(list.get(0).getScItemCategoryId());

        contractSDO.setAnnualQuantity(list.stream().filter(x->x.getAnnualQuantity()!=null).mapToInt(ContractSDO::getAnnualQuantity).sum());
        contractSDO.setAnnualAmount(list.stream().filter(x->x.getAnnualAmount()!=null).mapToLong(ContractSDO::getAnnualAmount).sum());
        contractSDO.setAnnualTaxIncludedBeforeTax(list.stream().filter(x->x.getAnnualTaxIncludedBeforeTax()!=null).mapToLong(ContractSDO::getAnnualTaxIncludedBeforeTax).sum());
//        contractSDO.setAnnualAfterDiscount(list.stream().filter(x->x.getAnnualAfterDiscount()!=null).mapToLong(ContractSDO::getAnnualAfterDiscount).sum());
        contractSDO.setJanQuantity(list.stream().filter(x->x.getJanQuantity()!=null).mapToInt(ContractSDO::getJanQuantity).sum());
        contractSDO.setFebQuantity(list.stream().filter(x->x.getFebQuantity()!=null).mapToInt(ContractSDO::getFebQuantity).sum());
        contractSDO.setMarQuantity(list.stream().filter(x->x.getMarQuantity()!=null).mapToInt(ContractSDO::getMarQuantity).sum());
        contractSDO.setAprQuantity(list.stream().filter(x->x.getAprQuantity()!=null).mapToInt(ContractSDO::getAprQuantity).sum());
        contractSDO.setMayQuantity(list.stream().filter(x->x.getMayQuantity()!=null).mapToInt(ContractSDO::getMayQuantity).sum());
        contractSDO.setJuneQuantity(list.stream().filter(x->x.getJuneQuantity()!=null).mapToInt(ContractSDO::getJuneQuantity).sum());
        contractSDO.setJulyQuantity(list.stream().filter(x->x.getJulyQuantity()!=null).mapToInt(ContractSDO::getJulyQuantity).sum());
        contractSDO.setAugQuantity(list.stream().filter(x->x.getAugQuantity()!=null).mapToInt(ContractSDO::getAugQuantity).sum());
        contractSDO.setSeptQuantity(list.stream().filter(x->x.getSeptQuantity()!=null).mapToInt(ContractSDO::getSeptQuantity).sum());
        contractSDO.setOctQuantity(list.stream().filter(x->x.getOctQuantity()!=null).mapToInt(ContractSDO::getOctQuantity).sum());
        contractSDO.setNovQuantity(list.stream().filter(x->x.getNovQuantity()!=null).mapToInt(ContractSDO::getNovQuantity).sum());
        contractSDO.setDecQuantity(list.stream().filter(x->x.getDecQuantity()!=null).mapToInt(ContractSDO::getDecQuantity).sum());
        contractSDO.setJanAmount(list.stream().filter(x->x.getJanAmount()!=null).mapToLong(ContractSDO::getJanAmount).sum());
        contractSDO.setFebAmount(list.stream().filter(x->x.getFebAmount()!=null).mapToLong(ContractSDO::getFebAmount).sum());
        contractSDO.setMarAmount(list.stream().filter(x->x.getMarAmount()!=null).mapToLong(ContractSDO::getMarAmount).sum());
        contractSDO.setAprAmount(list.stream().filter(x->x.getAprAmount()!=null).mapToLong(ContractSDO::getAprAmount).sum());
        contractSDO.setMayAmount(list.stream().filter(x->x.getMayAmount()!=null).mapToLong(ContractSDO::getMayAmount).sum());
        contractSDO.setJuneAmount(list.stream().filter(x->x.getJuneAmount()!=null).mapToLong(ContractSDO::getJuneAmount).sum());
        contractSDO.setJulyAmount(list.stream().filter(x->x.getJulyAmount()!=null).mapToLong(ContractSDO::getJulyAmount).sum());
        contractSDO.setAugAmount(list.stream().filter(x->x.getAugAmount()!=null).mapToLong(ContractSDO::getAugAmount).sum());
        contractSDO.setSeptAmount(list.stream().filter(x->x.getSeptAmount()!=null).mapToLong(ContractSDO::getSeptAmount).sum());
        contractSDO.setOctAmount(list.stream().filter(x->x.getOctAmount()!=null).mapToLong(ContractSDO::getOctAmount).sum());
        contractSDO.setNovAmount(list.stream().filter(x->x.getNovAmount()!=null).mapToLong(ContractSDO::getNovAmount).sum());
        contractSDO.setDecAmount(list.stream().filter(x->x.getDecAmount()!=null).mapToLong(ContractSDO::getDecAmount).sum());
//        contractSDO.setJanAfterDiscount(list.stream().filter(x->x.getJanAfterDiscount()!=null).mapToLong(ContractSDO::getJanAfterDiscount).sum());
//        contractSDO.setFebAfterDiscount(list.stream().filter(x->x.getFebAfterDiscount()!=null).mapToLong(ContractSDO::getFebAfterDiscount).sum());
//        contractSDO.setMarAfterDiscount(list.stream().filter(x->x.getMarAfterDiscount()!=null).mapToLong(ContractSDO::getMarAfterDiscount).sum());
//        contractSDO.setAprAfterDiscount(list.stream().filter(x->x.getAprAfterDiscount()!=null).mapToLong(ContractSDO::getAprAfterDiscount).sum());
//        contractSDO.setMayAfterDiscount(list.stream().filter(x->x.getMayAfterDiscount()!=null).mapToLong(ContractSDO::getMayAfterDiscount).sum());
//        contractSDO.setJuneAfterDiscount(list.stream().filter(x->x.getJuneAfterDiscount()!=null).mapToLong(ContractSDO::getJuneAfterDiscount).sum());
//        contractSDO.setJulyAfterDiscount(list.stream().filter(x->x.getJulyAfterDiscount()!=null).mapToLong(ContractSDO::getJulyAfterDiscount).sum());
//        contractSDO.setAugAfterDiscount(list.stream().filter(x->x.getAugAfterDiscount()!=null).mapToLong(ContractSDO::getAugAfterDiscount).sum());
//        contractSDO.setSeptAfterDiscount(list.stream().filter(x->x.getSeptAfterDiscount()!=null).mapToLong(ContractSDO::getSeptAfterDiscount).sum());
//        contractSDO.setOctAfterDiscount(list.stream().filter(x->x.getOctAfterDiscount()!=null).mapToLong(ContractSDO::getOctAfterDiscount).sum());
//        contractSDO.setNovAfterDiscount(list.stream().filter(x->x.getNovAfterDiscount()!=null).mapToLong(ContractSDO::getNovAfterDiscount).sum());
//        contractSDO.setDecAfterDiscount(list.stream().filter(x->x.getDecAfterDiscount()!=null).mapToLong(ContractSDO::getDecAfterDiscount).sum());
        contractSDO.setJanTaxIncludedBeforeTax(list.stream().filter(x->x.getJanTaxIncludedBeforeTax()!=null).mapToLong(ContractSDO::getJanTaxIncludedBeforeTax).sum());
        contractSDO.setFebTaxIncludedBeforeTax(list.stream().filter(x->x.getFebTaxIncludedBeforeTax()!=null).mapToLong(ContractSDO::getFebTaxIncludedBeforeTax).sum());
        contractSDO.setMarTaxIncludedBeforeTax(list.stream().filter(x->x.getMarTaxIncludedBeforeTax()!=null).mapToLong(ContractSDO::getMarTaxIncludedBeforeTax).sum());
        contractSDO.setAprTaxIncludedBeforeTax(list.stream().filter(x->x.getAprTaxIncludedBeforeTax()!=null).mapToLong(ContractSDO::getAprTaxIncludedBeforeTax).sum());
        contractSDO.setMayTaxIncludedBeforeTax(list.stream().filter(x->x.getMayTaxIncludedBeforeTax()!=null).mapToLong(ContractSDO::getMayTaxIncludedBeforeTax).sum());
        contractSDO.setJuneTaxIncludedBeforeTax(list.stream().filter(x->x.getJuneTaxIncludedBeforeTax()!=null).mapToLong(ContractSDO::getJuneTaxIncludedBeforeTax).sum());
        contractSDO.setJulyTaxIncludedBeforeTax(list.stream().filter(x->x.getJulyTaxIncludedBeforeTax()!=null).mapToLong(ContractSDO::getJulyTaxIncludedBeforeTax).sum());
        contractSDO.setAugTaxIncludedBeforeTax(list.stream().filter(x->x.getAugTaxIncludedBeforeTax()!=null).mapToLong(ContractSDO::getAugTaxIncludedBeforeTax).sum());
        contractSDO.setSeptTaxIncludedBeforeTax(list.stream().filter(x->x.getSeptTaxIncludedBeforeTax()!=null).mapToLong(ContractSDO::getSeptTaxIncludedBeforeTax).sum());
        contractSDO.setOctTaxIncludedBeforeTax(list.stream().filter(x->x.getOctTaxIncludedBeforeTax()!=null).mapToLong(ContractSDO::getOctTaxIncludedBeforeTax).sum());
        contractSDO.setNovTaxIncludedBeforeTax(list.stream().filter(x->x.getNovTaxIncludedBeforeTax()!=null).mapToLong(ContractSDO::getNovTaxIncludedBeforeTax).sum());
        contractSDO.setDecTaxIncludedBeforeTax(list.stream().filter(x->x.getDecTaxIncludedBeforeTax()!=null).mapToLong(ContractSDO::getDecTaxIncludedBeforeTax).sum());
    }

    private String getkey(ContractSDO contractSDO){
        StringBuilder key = new StringBuilder();
        key.append(contractSDO.getOrgBusinessUnitCode())
                .append("#")
                .append(contractSDO.getScItemCategoryId());
        return key.toString();
    }

}
